//go:build js || wasm

package godom

import "syscall/js"

// NodeWrapper
// https://developer.mozilla.org/ru/docs/Web/API/Node
type NodeWrapper interface {
	EventTargetWrapper

	BaseURI() string
	ChildNodes() NodeList
	IsConnected() bool
	FirstChild() Node
	NextSibling() Node
	NodeName() string
	NodeType() string
	NodeValue() string
	OwnerDocument() Document
	ParentElement() *Element
	ParentNode() Node
	PreviousSibling() Node
	TextContent() string
	SetTextContent(content string)

	AppendChild(node NodeWrapper)
	CloneNode(deep bool) Node
	CompareDocumentPosition(otherNode Node) int
	Contains(node Node) bool
	GetRootNode() Node
	HasChildNodes() bool
	InsertBefore(node Node, beforeNode Node) bool
	IsDefaultNamespace() bool
	IsEqualNode(node Node) bool
	IsSameNode(node Node) bool
	LookupNamespaceURI(prefix string) string
	LookupPrefix(namespace string) string
	Normalize()
	RemoveChild(node Node) Node
	ReplaceChild(node, oldNode Node) Node
}

type Node struct {
	jsValue js.Value
}

type NodeList []Node

func (n *Node) BaseURI() string {
	return n.jsValue.Get("baseURI").String()
}

func (n *Node) ChildNodes() NodeList {
	//todo: протестировать и реализовать
	return NodeList{}
}

func (n *Node) IsConnected() bool {
	return n.jsValue.Call("isConnected").Bool()
}

func (n *Node) FirstChild() Node {
	return Node{n.jsValue.Get("firstChild")}
}

func (n *Node) NextSibling() Node {
	return Node{n.jsValue.Get("nextSibling")}
}

func (n *Node) NodeName() string {
	return n.jsValue.Get("nodeName").String()
}

func (n *Node) NodeType() string {
	return n.jsValue.Get("nodeType").String()
}

func (n *Node) NodeValue() string {
	return n.jsValue.Get("nodeValue").String()
}

func (n *Node) OwnerDocument() Document {
	return Document{Node{jsValue: n.jsValue.Get("ownerDocument")}}
}

func (n *Node) ParentElement() *Element {
	return &Element{Node{jsValue: n.jsValue.Get("parentElement")}}
}

func (n *Node) ParentNode() Node {
	return Node{n.jsValue.Get("parentNode")}
}

func (n *Node) PreviousSibling() Node {
	return Node{n.jsValue.Get("previousSibling")}
}

func (n *Node) TextContent() string {
	return n.jsValue.Get("textContent").String()
}

func (n *Node) SetTextContent(content string) {
	n.jsValue.Set("textContent", content)
}

func (n *Node) AppendChild(node NodeWrapper) {
	n.jsValue.Call("appendChild", node.JSValue())
}

func (n *Node) CloneNode(deep bool) Node {
	return Node{n.jsValue.Call("cloneNode", deep)}
}

func (n *Node) CompareDocumentPosition(otherNode Node) int {
	return n.jsValue.Call("compareDocumentPosition", otherNode.jsValue).Int()
}

func (n *Node) Contains(node Node) bool {
	return n.jsValue.Call("contains", node.jsValue).Bool()
}

func (n *Node) GetRootNode() Node {
	return Node{n.jsValue.Call("rootNode")}
}

func (n *Node) HasChildNodes() bool {
	return n.jsValue.Call("hasChildNodes").Bool()
}

func (n *Node) InsertBefore(node Node, beforeNode Node) bool {
	return n.jsValue.Call("insertBefore", node.jsValue, beforeNode.jsValue).Bool()
}

func (n *Node) IsDefaultNamespace() bool {
	return n.jsValue.Get("isDefaultNamespace").Bool()
}

func (n *Node) IsEqualNode(node Node) bool {
	return n.jsValue.Call("isEqual", node.jsValue).Bool()
}

func (n *Node) IsSameNode(node Node) bool {
	return n.jsValue.Call("isSame", node.jsValue).Bool()
}

func (n *Node) LookupNamespaceURI(prefix string) string {
	return n.jsValue.Call("lookupNamespaceURI", prefix).String()
}

func (n *Node) LookupPrefix(namespace string) string {
	return n.jsValue.Call("lookupPrefix", namespace).String()
}

func (n *Node) Normalize() {
	n.jsValue.Call("normalize")
}

func (n *Node) RemoveChild(node Node) Node {
	return Node{n.jsValue.Call("removeChild", node.jsValue)}
}

func (n *Node) ReplaceChild(newChild Node, oldChild Node) Node {
	return Node{n.jsValue.Call("replaceChild", newChild.jsValue, oldChild.jsValue)}
}

func (n *Node) AddEventListener(event string, handler js.Func) {
	n.jsValue.Call("addEventListener", event, handler)
}

func (n *Node) DispatchEvent(event string) {
	n.jsValue.Call("deleteEventListener", event)
}

func (n *Node) RemoveEventListener(event string, handler js.Func) {
	n.jsValue.Call("removeEventListener", event, handler)
}

func (n *Node) JSValue() js.Value {
	return n.jsValue
}

// NodeIteratorWrapper
// https://developer.mozilla.org/en-US/docs/Web/API/NodeIterator
type NodeIteratorWrapper interface {
	JSWrapper

	Filter() js.Value
	PointerBeforeReferenceNode() bool
	ReferenceNode() Node
	Root() Node
	WhatToShow() int
}

type NodeIterator struct {
	jsValue js.Value
}

func (n *NodeIterator) Filter() js.Value {
	return n.jsValue.Get("filter")
}

func (n *NodeIterator) PointerBeforeReferenceNode() bool {
	return n.jsValue.Get("pointerBeforeReferenceNode").Bool()
}

func (n *NodeIterator) ReferenceNode() Node {
	return Node{n.jsValue.Get("referenceNode")}
}

func (n *NodeIterator) Root() Node {
	return Node{n.jsValue.Get("root")}
}

func (n *NodeIterator) WhatToShow() int {
	return n.jsValue.Get("whatToShow").Int()
}

func (n *NodeIterator) JSValue() js.Value {
	return n.jsValue
}
